package com.cvdnn.serial;

import android.IRes;
import android.annotation.SuppressLint;
import android.assist.Assert;
import android.io.Stream;
import android.log.Log;
import android.math.Maths;

import androidx.annotation.NonNull;
import androidx.annotation.RawRes;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.nio.charset.StandardCharsets.ISO_8859_1;

/**
 * 语义化版本号
 */
public final class Semver {
    private static final String TAG = "Nooks";

    public enum Cells {
        SOFTWARE(0), HARDWARE(1), HAREWARE(1), BUILD(2);

        public final int index;

        Cells(int i) {
            index = i;
        }
    }

    public static final int OFFSET_VERSION_TEXT = 0x0800;
    public static final int LEN_VERSION_TEXT = 64;

    public static final long MASK_VERSION_CODE = -1L;
    public static final int INDEX_START = -1;

    @SuppressLint("NewApi")
    public static List<Semver> load(int... roms) {
        List<Semver> verList = null;

        if (Assert.notEmpty(roms)) {
            try {
                verList = Arrays.asList(Arrays.stream(roms).mapToObj(rawRes -> new Semver().parse(rawRes)).toArray(Semver[]::new));
            } catch (Throwable t) {
                Log.d(t);
            }
        } else {
            verList = new ArrayList<>(0);
        }

        return verList;
    }

    public static boolean valid(Semver... svs) {
        boolean result = true;
        if (Assert.notEmpty(svs)) {
            for (Semver ver : svs) {
                result &= (ver != null && ver.valid());
                if (!result) {
                    break;
                }
            }
        }

        return result;
    }

    /**
     * 判断是否是3.xROM
     *
     * @param ver
     *
     * @return
     */
    @Deprecated
    public static boolean is3xRom(Semver ver) {
        return valid(ver) && ver.rom.startsWith("3.") || ver.rom.contains("Software:V3.");
    }

    /**
     * 判断是否是4.xROM
     *
     * @param ver
     *
     * @return
     */
    @Deprecated
    public static boolean is4xRom(Semver ver) {
        return valid(ver) && ver.rom.startsWith("4.") || ver.rom.contains("Software:V4.");
    }

    /////////////////////////////////////
    //

    /** PCB版本号 */
    public String pcb = "";

    /** ROM版本号 */
    public String rom = "";

    public long code = MASK_VERSION_CODE;

    public Semver() {

    }

    /**
     * Software:V3.0,Hareware:V0.3
     * 4.0,0.3,202007022132
     *
     * @param text
     *
     * @return
     */
    public Semver parse(String text) {
        if (Assert.notEmpty(text)) {
            String[] verArray = text.split(",");
            for (int i = 0; i < verArray.length; i++) {
                parse(i, verArray[i]);
            }
        }

        return this;
    }

    public Semver parse(@RawRes int rawRes) {
        return parse(IRes.openRawRes(rawRes));
    }

    public Semver parse(File binFile) {
        try {
            parse(new FileInputStream(binFile));
        } catch (Exception e) {
            Log.w(TAG, e);
        }

        return this;
    }

    public Semver parse(InputStream in) {
        if (in != null) {
            BufferedInputStream bin = null;

            try {
                bin = new BufferedInputStream(in);
                // 跳转到指定字节
                bin.skip(OFFSET_VERSION_TEXT);

                String key = "", value = "";
                byte[] buff = new byte[LEN_VERSION_TEXT];
                final int blockLen = bin.read(buff, 0, buff.length);
                if (blockLen > 0) {
                    int start = INDEX_START, cursor = 0, index = 0;
                    while (cursor < blockLen) {
                        int temp = buff[cursor];

                        // 判断是否是可见字符
                        if (temp >= 0x20 && temp <= 0x7E) {
                            // 从第1个可见字符开始
                            if (start == INDEX_START) {
                                start = cursor;
                            }

                            // 模块开始标识
                            if (temp == ':') {
                                if (start >= 0 && cursor - start > 0) {
                                    key = new String(buff, start, cursor - start, ISO_8859_1);

                                    // 指向下一字符
                                    start = cursor + 1;
                                }

                                // 模块分隔符
                            } else if (temp == ',') {
                                if (start >= 0 && cursor - start > 0) {
                                    value = findValue(buff, start, cursor);
                                    if (Assert.notEmpty(key)) {
                                        set(key, value);

                                    } else {
                                        set(index, value);

                                        index++;
                                    }

                                    // 指向下一字符
                                    start = cursor + 1;
                                    key = "";
                                }
                            }

                            cursor++;

                            // 跳过前导0x00
                        } else if (start == INDEX_START) {
                            cursor++;

                            // 作为结束符
                        } else {
                            if (start >= 0) {
                                if (cursor - start > 0) {
                                    value = findValue(buff, start, cursor);
                                    if (Assert.notEmpty(key)) {
                                        set(key, value);

                                    } else {
                                        set(index, value);

                                        index++;
                                    }
                                }
                            }

                            break;
                        }
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, e);

            } finally {
                Stream.close(bin);
            }
        }

        return this;
    }

    public void set(String tag, String ver) {
        if (equals(Cells.SOFTWARE, tag)) {
            rom = ver;

        } else if (equals(Cells.HARDWARE, tag)) {
            pcb = ver;

        } else if (equals(Cells.HAREWARE, tag)) {
            pcb = ver;

        } else if (equals(Cells.BUILD, tag)) {
            code = Maths.valueOf(ver, MASK_VERSION_CODE);
        }
    }

    public void set(int index, String ver) {
        if (equals(Cells.SOFTWARE, index)) {
            rom = ver;

        } else if (equals(Cells.HARDWARE, index)) {
            pcb = ver;

        } else if (equals(Cells.HAREWARE, index)) {
            pcb = ver;

        } else if (equals(Cells.BUILD, index)) {
            code = Maths.valueOf(ver, MASK_VERSION_CODE);
        }
    }

    private void parse(int index, String text) {
        if (Assert.notEmpty(text)) {
            if (text.contains(":")) {
                String[] arrays = text.split(":");
                set(arrays[0], findValue(arrays[1]));

            } else {
                set(index, findValue(text));
            }
        }

    }

    private static String findValue(byte[] buff, int start, int end) {
        String text = "";

        if (buff[start] == 'V' || buff[start] == 'v') {
            start++;
        }

        if (start >= 0 && end - start > 0) {
            text = new String(buff, start, end - start, ISO_8859_1);
        }

        return text;
    }

    /**
     * 过滤掉'V'/'v'
     *
     * @param t
     *
     * @return
     */
    private String findValue(String t) {
        String ver = "";

        if (Assert.notEmpty(t)) {
            int len = t.length();
            char c = t.charAt(0);
            if (c == 'V' || c == 'v') {
                if (len > 1) {
                    ver = t.substring(1);
                }
            } else {
                ver = t;
            }
        }

        return ver;
    }

    public int findRawRes() {
        return IRes.idRaw(String.format("rubbish%dx", major()));
    }

    public Semver findRawSemver() {
        return new Semver().parse(findRawRes());
    }

    public InputStream openRawRes() {
        return IRes.openRawRes(findRawRes());
    }

    public boolean equals(@NonNull Cells m, String t) {

        return m.name().equalsIgnoreCase(t) || Assert.notEmpty(t) && t.toUpperCase().contains(m.name());
    }

    public boolean equals(@NonNull Cells m, int i) {
        return m.index == i;
    }

    /**
     * 获取主版本号
     *
     * @return
     */
    public int major() {
        int major = (int) MASK_VERSION_CODE;

        if (Assert.notEmpty(rom)) {
            int index = rom.indexOf('.');
            if (index > 0) {
                major = Maths.valueOf(rom.substring(0, index), 0);
            } else {
                major = Maths.valueOf(rom, 0);
            }
        }

        return major;
    }

    public boolean newness(Semver semver) {

        return major() == semver.major() && code > semver.code;
    }

    public boolean valid() {
        return major() != MASK_VERSION_CODE && Assert.notEmpty(pcb);
    }

    public String toVersion() {
        StringBuilder text = new StringBuilder();
        text.append("V").append(rom).append("_").append(pcb);

        if (code != MASK_VERSION_CODE) {
            text.append("_Build_").append(code);
        } else {
            text.append("_Legacy");
        }

        return text.toString();
    }

    @Override
    public String toString() {
        return new StringBuilder("V").append(rom).append("_").append(pcb).append("_Build_").append(code).toString();
    }
}
